package com.shenma2009;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.ArrayList;

@SpringBootTest
public class HbaseTestApplication {
    private Connection connection;
    private HTable table;
    HBaseAdmin admin;

    // https://www.jianshu.com/p/046ed8cac2f1
    // https://zhuanlan.zhihu.com/p/138768143
    // https://zhuanlan.zhihu.com/p/138768143
    // https://blog.csdn.net/weixin_42641909/article/details/89428976

    @Before
    public void init() throws IOException {
        Configuration configuration = HBaseConfiguration.create();
        //设置zookeeper的地址，可以有多个，以逗号分隔
        configuration.set("hbase.zookeeper.quorum","192.168.80.130");
        //设置zookeeper的端口
        configuration.set("hbase.zookeeper.property.clientPort","2181");

        configuration.set("hbase.master", "192.168.80.130:16000");
        configuration.set("hbase.zookeeper.znode", "/hbase");
        configuration.set("hbase.client.keyvalue.maxsize", "1572864000");

//        configuration.set("hadoop.home.dir", "");
        //创建hbase的连接，这是一个分布式连接
        connection = ConnectionFactory.createConnection(configuration);
        //获取hbase中的表
        table = (HTable) connection.getTable(TableName.valueOf("user"));

        //这个admin是管理table时使用的，比如说创建表
        admin = (HBaseAdmin) connection.getAdmin();
    }

    /**
     * @description 检查表是否存在
     * @author 军哥
     * @date 2023/5/30 9:34
     * @version 1.0
     */
    @Test
    public void checkTable() throws IOException {
        //声明一个表名
        TableName tableName = TableName.valueOf("shenmazong", "student");
        boolean tableExists = admin.tableExists(tableName);
        if(tableExists) {
            System.out.println("表存在");
        }
        else {
            System.out.println("表不存在");
        }
    }

    /**
     * @description 创建命名空间
     * @author 军哥
     * @date 2023/5/30 10:07
     * @version 1.0
     */
    @Test
    public void testCreatNamespace() throws IOException {
        String namespace = "shenmazong";
        // 创建命令空间描述建造者 => 设计师
        NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);

        // 给命令空间添加需求
        builder.addConfiguration("author","andy");
        builder.addConfiguration("date","2023-05-30");

        // 使用 builder 构造出对应的添加完参数的对象 完成创建
        // 创建命名空间出现的问题 都属于本方法自身的问题 不应该抛出
        admin.createNamespace(builder.build());
    }

    /**
     * @description 创建表，创建表只需要指定列族，不需要指定列
     * 其实用命令真的会更快，create 'user','info1','info2'
     * @author 军哥
     * @date 2023/5/30 9:29
     * @version 1.0
     */
    @Test
    public void createTable() throws IOException {
        //声明一个表名
        TableName tableName = TableName.valueOf("shenmazong", "student");

        //构造一个表的描述
        TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(tableName);

        // 定义表的列族
        ArrayList<String> families = new ArrayList<>();
        families.add("person");
        families.add("company");

        families.forEach(columnFamily -> {
            // 创建表的描述
            ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(columnFamily));

            // 添加版本参数
            columnFamilyDescriptorBuilder.setMaxVersions(5);

            // 创建添加完参数的列族描述
            tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptorBuilder.build());
        });

        // 创建表
        admin.createTable(tableDescriptorBuilder.build());
    }

    /**
     * @description 在表中插入数据
     * @author 军哥
     * @date 2023/5/30 10:08
     * @version 1.0
     */
    @Test
    public void addDataToTable() throws IOException {
        String namespace = "shenmazong";
        String tableName = "student";
        String rowKey = "001";
        String columnFamily = "person";
        String columnName = "name";
        String value = "andy";

        // 获取 table
        Table table = connection.getTable(TableName.valueOf(namespace, tableName));

        // 创建 put 对象
        Put put = new Put(Bytes.toBytes(rowKey));

        // 给 put 对象添加数据
        put.addColumn(Bytes.toBytes(columnFamily),Bytes.toBytes(columnName),Bytes.toBytes(value));

        // 将对象写入对应的方法
        table.put(put);

        // 关闭 table
        table.close();
    }

    /**
     * @description TODO
     * @author 军哥
     * @date 2023/5/30 10:26
     * @version 1.0
     * shell cmd: scan 'shenmazong:student'
     */
    @Test
    public void listTableRows() throws IOException {
        String namespace = "shenmazong";
        String tableName = "student";
        String startRow = "001";
        String stopRow = "003";

        // 1. 获取 table
        Table table = connection.getTable(TableName.valueOf(namespace, tableName));
        // 2. 创建 scan 对象
        Scan scan = new Scan();
        // 如果此时直接调用 会直接扫描整张表
        // 添加参数 来控制扫描的数据
        // 默认包含
        scan.withStartRow(Bytes.toBytes(startRow));
        // 默认不包含
        scan.withStopRow(Bytes.toBytes(stopRow));
        try {
            // 读取多行数据 获得 scanner
            ResultScanner scanner = table.getScanner(scan);
            // result 来记录一行数据 cell 数组
            // ResultScanner 来记录多行数据 result 的数组
            for (Result result : scanner) {
                Cell[] cells = result.rawCells();
                for (Cell cell : cells) {
                    System.out.print (new
                            String(CellUtil.cloneRow(cell)) + "-" + new
                            String(CellUtil.cloneFamily(cell)) + "-" + new
                            String(CellUtil.cloneQualifier(cell)) + "-" + new
                            String(CellUtil.cloneValue(cell)) + "\t");
                }
                System.out.println();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 3. 关闭 table
        table.close();
    }

    @Test
    public void readRowOne() throws IOException {
        String namespace = "shenmazong";
        String tableName = "student";
        String rowKey = "001";
        String columnFamily = "person";
        String columnName = "name";

        // 1. 获取 table
        Table table = connection.getTable(TableName.valueOf(namespace, tableName));

        // 2. 创建 get 对象
        Get get = new Get(Bytes.toBytes(rowKey));

        // 如果直接调用 get 方法读取数据 此时读一整行数据
        // 如果想读取某一列的数据 需要添加对应的参数
        get.addColumn(Bytes.toBytes(columnFamily),
                Bytes.toBytes(columnName));

        // 设置读取数据的版本
        get.readAllVersions();
//        get.readVersions(get.getMaxVersions());


        // 读取数据 得到 result 对象
        Result result = table.get(get);
        // 处理数据
        Cell[] cells = result.rawCells();
        // 测试方法: 直接把读取的数据打印到控制台
        // 如果是实际开发 需要再额外写方法 对应处理数据
        for (Cell cell : cells) {
            // cell 存储数据比较底层
            String value = new String(CellUtil.cloneValue(cell));
            System.out.println(value);
        }

        // 关闭 table
        table.close();

    }

    /**
     * @description 删除记录
     * @author 军哥
     * @date 2023/5/30 10:48
     * @version 1.0
     */
    @Test
    public void testDeleteRow() throws IOException {
        String nameSpace = "shenmazong";
        String tableName = "student";
        String rowKey = "001";
        String columnFamily = "person";
        String columnName = "name";

        // 1.获取 table
        Table table = connection.getTable(TableName.valueOf(nameSpace, tableName));
        // 2.创建 Delete 对象
        Delete delete = new Delete(Bytes.toBytes(rowKey));
        // 3.添加删除信息
        // 3.1 删除单个版本
        //
        delete.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(columnName));

        // 3.2 删除所有版本，多了一个s
        //delete.addColumns(Bytes.toBytes(columnFamily), Bytes.toBytes(columnName));

        // 3.3 删除列族
        // delete.addFamily(Bytes.toBytes(family));

        // 3.删除数据
        table.delete(delete);
        // 5.关闭资源
        table.close();
    }

    /**
     * @description 删除表
     * @author 军哥
     * @date 2023/5/30 10:53
     * @version 1.0
     */
    @Test
    public void deleteTable() {
        String nameSpace = "shenmazong";
        String tableName = "student";

        // 调用相关的方法删除表格
        try {
            // HBase 删除表格之前 一定要先标记表格为不可以
            TableName tableName1 = TableName.valueOf(nameSpace, tableName);
            admin.disableTable(tableName1);
            admin.deleteTable(tableName1);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void deleteNamespace() throws IOException {
        String nameSpace = "shenmazong";

        admin.deleteNamespace(nameSpace);
    }
}
